//
//  Email.m
//  YuchBox
//
//  Created by Ivan on 11-10-7.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import "Email.h"
#import "Utility.h"

typedef enum {
    DBUid           =   0,
    DBAccountUid,
    DBHashCode,
    DBIndex,
    DBFrom,
    DBReply,
    DBCc,
    DBBcc,
    DBTo,
    DBGroup,
    DBSubject,
    DBXmailName,
    DBContent,
    DBConetetHtml,
    DBSendTimestamp,
    DBFlag,
    DBSendStyle,
    DBStatus
} DBEmailFieldIndex;

@implementation Email

@synthesize index           = _index;
@synthesize uid             = _uid;
@synthesize accountUid      = _accountUid;
//@synthesize hashCode        = _hashCode;
@synthesize version         = _version;

@synthesize fromArray       = _fromArray;
@synthesize replyToArray    = _replyToArray;
@synthesize ccToArray       = _ccToArray;
@synthesize bccToArray      = _bccToArray;
@synthesize toArray         = _toArray;
@synthesize groupArray      = _groupArray;

@synthesize fromString      = _fromString;
@synthesize replyToString   = _replyToString;
@synthesize ccToString      = _ccToString;
@synthesize bccToString     = _bccToString;
@synthesize toString        = _toString;
@synthesize groupString     = _groupString;

@synthesize subject         = _subject;
@synthesize xmailName       = _xmailName;
@synthesize content         = _content;
@synthesize contentHtml     = _contentHtml;
@synthesize sendDate        = _sendDate;
@synthesize sendTimestamp    = _sendTimestamp;

@synthesize attachmentArray = _attachmentArray;

@synthesize flag            = _flag;
@synthesize status          = _status;
@synthesize hasLocationInfo = _hasLocationInfo;

// for version >= 2
@synthesize contentHtmlType = _contentHtmlType;

//
@synthesize sendStyle       = _sendStyle;
@synthesize doWannaSave     = _doWannaSave;

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
        _fromArray       = [[NSMutableArray alloc] init];
        _replyToArray    = [[NSMutableArray alloc] init];
        _ccToArray       = [[NSMutableArray alloc] init];
        _bccToArray      = [[NSMutableArray alloc] init];
        _toArray         = [[NSMutableArray alloc] init];
        _groupArray      = [[NSMutableArray alloc] init];
    
        _attachmentArray = [[NSMutableArray alloc] init];
//        
//        _subject       = [NSMutableString string];
//        _xmailName     = [NSMutableString string];
//        _content       = [NSMutableString string];  
//        _contentHtml   = [NSMutableString string];
        
        _flag            = 0;
        _hashCode        = 0;
        _sendStyle       = EMAIL_SEND_STYLE_NOTHING;
        _doWannaSave     = NO;
        
        _sendDate        = [[NSDate alloc] init];
        
        _status          = EMAIL_STATUS_RECV_UNREAD;
    }
    
    return self;
}

- (void)dealloc
{
    [_fromArray release];
    [_replyToArray release];
    [_ccToArray release];
    [_bccToArray release];
    [_toArray release];
    [_groupArray release];
    
    [_attachmentArray release];
    
    [_sendDate release];
    [super dealloc];
    
    self = nil;
}


- (id)initWithInputStream:(NSInputStream *)inStream
{
    self = [self init];
    if (self) {
        // Initialization code here.
        _version = [StreamPeer readInt8WithInstream:inStream];
        //_uid     = [StreamPeer readInt32WithInStream:inStream];
        _index   = [StreamPeer readInt32WithInStream:inStream];
        
        [StreamPeer readArrayWithInStream:inStream outArray:_fromArray];

        [StreamPeer readArrayWithInStream:inStream outArray:_replyToArray];
        [StreamPeer readArrayWithInStream:inStream outArray:_ccToArray];
        [StreamPeer readArrayWithInStream:inStream outArray:_bccToArray];
        [StreamPeer readArrayWithInStream:inStream outArray:_toArray];
        [StreamPeer readArrayWithInStream:inStream outArray:_groupArray];

        _fromString     = UTIL_IMPLODE_SEMICO(_fromArray);
        _replyToString  = UTIL_IMPLODE_SEMICO(_replyToArray);
        _ccToString     = UTIL_IMPLODE_SEMICO(_ccToArray);
        _bccToString    = UTIL_IMPLODE_SEMICO(_bccToArray);
        _toString       = UTIL_IMPLODE_SEMICO(_toArray);
        _groupString    = UTIL_IMPLODE_SEMICO(_groupArray);
        
        
        _subject    = [StreamPeer readStringWithInStream:inStream];
        
        // get 8 bytes timestamp
        UInt32 *ptr = (UInt32 *)&_sendTimestamp;
        ptr[0] = [StreamPeer readInt32WithInStream:inStream];
        ptr[1] = [StreamPeer readInt32WithInStream:inStream];
        [_sendDate initWithTimeIntervalSince1970:(NSTimeInterval)(_sendTimestamp/1000)];
        
        //
        _flag           = [StreamPeer readInt32WithInStream:inStream];
        _xmailName      = [StreamPeer readStringWithInStream:inStream];
        _content        = [StreamPeer readStringWithInStream:inStream];
        _contentHtml    = [StreamPeer readStringWithInStream:inStream];
        
        //TTDUMP((UInt8*)[_content UTF8String], [_contentHtml length]);
        //
        //_attachmentArray
        NSInteger attachmentCount = [StreamPeer readInt32WithInStream:inStream];
        for (int i = 0 ; i < attachmentCount ; i++) {
            Attachment * attachment = [[Attachment alloc] initWithInputStream:inStream];
            attachment.mailIndex        = _index;
            attachment.attachmentIndex  = i;
            attachment.timestamp        = _sendTimestamp;
            
            [_attachmentArray addObject:attachment];
            [attachment release];
        }
                
        _hasLocationInfo = [StreamPeer readInt8WithInstream:inStream];
        
        _hashCode = [self getHashCode];
        
        if (_version >= 2) {
            _contentHtmlType = [StreamPeer readStringWithInStream:inStream];
        }
    }
    
    return self;
}


- (void)outputMail:(NSOutputStream *)outStream
{
    
    [StreamPeer writeInt8WithOutStream:outStream int8Value:(UInt8)_version];
    [StreamPeer writeInt32WithOutStream:outStream intValue:_index];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_fromArray];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_replyToArray];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_ccToArray];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_bccToArray];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_toArray];
    [StreamPeer writeArrayWithOutStream:outStream arrayValue:_groupArray];
    
    [StreamPeer writeStringWithOutStream:outStream stringValue:_subject];
    [StreamPeer writeInt64WithOutStream:outStream int64Value:_sendTimestamp];
    [StreamPeer writeInt32WithOutStream:outStream intValue:_flag];
    
    [StreamPeer writeStringWithOutStream:outStream stringValue:_xmailName];
    [StreamPeer writeStringWithOutStream:outStream stringValue:_content];
    [StreamPeer writeStringWithOutStream:outStream stringValue:_contentHtml];
    
    
    // the attachment info 
    
    [StreamPeer writeInt32WithOutStream:outStream intValue:[_attachmentArray count]];
    for (Attachment *attachment in _attachmentArray) {
        [StreamPeer writeInt32WithOutStream:outStream intValue:attachment.attachmentSize];
        [StreamPeer writeStringWithOutStream:outStream stringValue:attachment.realName];
        [StreamPeer writeStringWithOutStream:outStream stringValue:attachment.type];
    }
    
    [StreamPeer writeInt8WithOutStream:outStream int8Value:_hasLocationInfo];
    if (_hasLocationInfo) {
        // GPS info
    }
    
    [StreamPeer writeStringWithOutStream:outStream stringValue:_contentHtmlType];
    [StreamPeer writeInt8WithOutStream:outStream int8Value:_sendStyle];
    
    if (EMAIL_SEND_STYLE_FORWORD == _sendStyle) {
        // TODO send the forword mail
    }
    
    // does want to copy to sent folder
    [StreamPeer writeInt8WithOutStream:outStream int8Value:_doWannaSave];
}


- (void)setSendDate:(NSDate *)sendDate
{
    if (_sendDate != sendDate) {
        [_sendDate release];
        _sendDate = [sendDate retain];
        _sendTimestamp = (UInt64)([_sendDate timeIntervalSince1970] * 1000);
    }
}

- (void)setSendTimestamp:(UInt64)sendTimestamp
{
    if (_sendTimestamp != sendTimestamp) {
        _sendTimestamp = sendTimestamp;
//        [_sendDate initWithTimeIntervalSince1970:(NSTimeInterval)(_sendTimestamp/1000)];
        [_sendDate release];
        _sendDate = [[NSDate alloc] initWithTimeIntervalSince1970:(NSTimeInterval)(_sendTimestamp/1000)];
    }
}

- (NSUInteger)getHashCode
{
    // !TODO TEST the hash whether it value equal to the java's hashcode()
    if (0 == _hashCode) {
        NSString *string = [NSString stringWithFormat:@"%@%llu",_subject,_sendTimestamp];
        _hashCode = [Utility getJavaStringHashCode:string];
    }
    return _hashCode;
}

- (void)save:(IvanSqliteDB *)con
{
    if (![con checkConnection]) {
        [con connect];
    }
    
#define IMPLODE_AND_ESCAPED(nsarray) SQLITE_TEXT_ESCAPED(UTIL_IMPLODE_SEMICO(nsarray))
    NSString *sql = [NSString stringWithFormat:@"INSERT INTO email VALUES( \
                     null, %llu, %lu, %d, '%@', '%@', \
                     '%@', '%@', '%@', '%@', '%@', \
                     '%@', '%@', '%@', %llu, %d, \
                     %d, %d)",
                     // id, auto increase
                     _accountUid,
                     _hashCode, 
                     _index, 
                     SQLITE_TEXT_ESCAPED(_fromString), 
                     SQLITE_TEXT_ESCAPED(_replyToString),
                     
                     SQLITE_TEXT_ESCAPED(_ccToString), 
                     SQLITE_TEXT_ESCAPED(_bccToString), 
                     SQLITE_TEXT_ESCAPED(_toString), 
                     SQLITE_TEXT_ESCAPED(_groupString), 
                     SQLITE_TEXT_ESCAPED(_subject),
                     
                     SQLITE_TEXT_ESCAPED(_xmailName), 
                     SQLITE_TEXT_ESCAPED(_content), 
                     SQLITE_TEXT_ESCAPED(_contentHtml), 
                     _sendTimestamp, 
                     _flag,
                     
                     _sendStyle,
                     _status];
    
    if (![con insertWithSql:sql]) {
        TTLOGF_ERROR(@"Insert/Update email <%d> error!", _hashCode);
        return;
    }
    
    _uid = [con getLastInsertRowid];
    
    //TTLOGF_INFO(@"%llu", [con getLastInsertRowid]);
}

- (void)chagneStatusToRead:(IvanSqliteDB *)con
{
    if (EMAIL_STATUS_RECV_ATTACH_READ == _status || EMAIL_STATUS_RECV_READ == _status) {
        return;
    }
    
    switch (_status) {
        case EMAIL_STATUS_RECV_UNREAD:
            [self changeStatus:EMAIL_STATUS_RECV_READ con:con];
            break;
        case EMAIL_STATUS_RECV_ATTACH_UNREAD:
            [self changeStatus:EMAIL_STATUS_RECV_ATTACH_READ con:con];
            break;
        default:
            break;
    }
}

- (void)changeStatus:(NSInteger)status con:(IvanSqliteDB *)con
{
    if (![con checkConnection]) {
        [con connect];
    }
    _status = status;
    NSString *sql = [NSString stringWithFormat:@"UPDATE email SET status=%d where id=%d", status, _uid];
    if (![con updateWithSql:sql]) {
        TTLOGF_ERROR(@"Update email(%d) status <%d> error!", _uid, _hashCode);
        return;
    }
}


+ (Email *)getOneEmailWith:(sqlite3_stmt *)stmt
{
    Email *email    = [[Email alloc] init];
    
    email.uid           = (UInt64)sqlite3_column_int64(stmt, DBUid);
    email.accountUid    = (UInt64)sqlite3_column_int64(stmt, DBAccountUid);
    email.index         = (UInt32)sqlite3_column_int(stmt, DBIndex);
    email.fromString    = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBFrom)];
    email.replyToString = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBReply)];
    email.ccToArray     = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBCc)];
    email.bccToString   = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBBcc)];
    email.toString      = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBTo)];
    email.groupString   = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBGroup)];
    //NSLog(@"%@",from);
    email.subject       = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBSubject)];
    email.content       = [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBContent)];
    email.contentHtml   = [NSString stringWithFormat:@"<div id='EmailContentHtml' style='color:white'>%@</div>", [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, DBConetetHtml)]];
    email.sendTimestamp = sqlite3_column_int64(stmt, DBSendTimestamp);
    
    email.status        = sqlite3_column_int(stmt, DBStatus);
    
    return [email autorelease];
}

+ (NSInteger)retrieveEmails:(IvanSqliteDB *)con emails:(NSMutableArray *)emails limit:(NSInteger)limit offset:(NSInteger)offset
{
    if (nil == con || ![con checkConnection]) {
        [con connect];
    }
    
   // NSMutableArray *emails = [[NSMutableArray alloc] init];
    NSString *sql = [NSString stringWithFormat:@"SELECT * FROM email ORDER BY send_timestamp DESC, id DESC limit %d offset %d", limit, offset];
    sqlite3_stmt *stmt = [con prepareSelect:sql];

    NSInteger loadNum = 0;
    while (SQLITE_ROW == sqlite3_step(stmt)) {

        Email *email = [Email getOneEmailWith:stmt];
        [Attachment retrieveAttachments:email.attachmentArray emailId:email.uid con:con];
        loadNum ++;
        [emails addObject:email];
    }
    
    return loadNum;
}

+ (Email *)retrieveEmail:(IvanSqliteDB *)con pkId:(UInt64)pkId
{
    if (nil == con || ![con checkConnection]) {
        [con connect];
    }
    
    NSString *sql = [NSString stringWithFormat:@"SELECT * FROM email WHERE id = %llu", pkId];
    sqlite3_stmt *stmt = [con prepareSelect:sql];
    if (SQLITE_ROW == sqlite3_step(stmt)) {
        Email *email = [Email getOneEmailWith:stmt];
        [Attachment retrieveAttachments:email.attachmentArray emailId:email.uid con:con];
        
        return email;
    }
//    
    return nil;
}

+ (NSInteger)getEmailTotal:(IvanSqliteDB *)con
{
    if (nil == con || ![con checkConnection]) {
        [con connect];
    }
    
    // NSMutableArray *emails = [[NSMutableArray alloc] init];
    NSString *sql = [NSString stringWithFormat:@"SELECT count(*) FROM email"];
    sqlite3_stmt *stmt = [con prepareSelect:sql];
    
    NSInteger totalNum = -1;
    while (SQLITE_ROW == sqlite3_step(stmt)) {
        totalNum = (UInt32)sqlite3_column_int(stmt, 0);
    }
    
    return totalNum;
}

+ (NSInteger)getEmailUnreadTotal:(IvanSqliteDB *)con
{
    if (nil == con || ![con checkConnection]) {
        [con connect];
    }
    
    // NSMutableArray *emails = [[NSMutableArray alloc] init];
    NSString *sql = [NSString stringWithFormat:@"SELECT count(*) FROM email where status in (%d, %d)", 
                     EMAIL_STATUS_RECV_UNREAD, 
                     EMAIL_STATUS_RECV_ATTACH_UNREAD];
    sqlite3_stmt *stmt = [con prepareSelect:sql];
    
    NSInteger totalNum = -1;
    while (SQLITE_ROW == sqlite3_step(stmt)) {
        totalNum = (UInt32)sqlite3_column_int(stmt, 0);
    }
    
    return totalNum;
}
@end

